package agent;

import java.util.List;

import aima.core.agent.Action;
import aima.core.agent.AgentProgram;
import aima.core.agent.Percept;
import aima.core.agent.impl.AbstractAgent;
import aima.core.agent.impl.DynamicAction;
import aima.core.agent.impl.NoOpAction;
import core.LocalVacuumEnvironmentPerceptTaskEnvironmentB;
import core.VacuumEnvironment.LocationState;

public class VacuumAgent1 extends AbstractAgent {

	static EnviromentMap envMap;
	static String movePrec;
	static boolean firstStep;
	static List<Action> solution;
	static int count;
	static double THRESHOLD_NOHOME_NODIRTY;
	static double THRESHOLD_NOHOME_DIRTY;
	static AgentState currentState;
	static AgentState lastState;
	static boolean homeFound;
	static boolean dirtyFound;

	public VacuumAgent1() {

		super(new AgentProgram() {

			@Override
			public Action execute(final Percept percept) {
				final LocalVacuumEnvironmentPerceptTaskEnvironmentB vep = (LocalVacuumEnvironmentPerceptTaskEnvironmentB) percept;
				String move = null;
				if (firstStep) {
					if (vep.getState().getLocState() == LocationState.Dirty) {
						dirtyFound = true;
					}

					envMap = new EnviromentMap(vep.getState().getLocState(), vep.getN(), vep.getM());
					move = envMap.getNextMove(vep.getCurrentEnergy());
					movePrec = move;
					firstStep = false;
				} else {

					if (vep.getCurrentEnergy() == 0)
						return NoOpAction.NO_OP;

					updateMap(vep);
//					printState();

					switch (currentState) {

					case NOHOME_NODIRTY:

						return new DynamicAction(getNewMove(vep));

					case HOME_NODIRTY:

						if (!envMap.comingBackHomeNO_Dirty)
							envMap.setPathToTheBase();
						if (vep.getCurrentEnergy() <= envMap.getPathToTheBase().size() + 1) {
							if (envMap.getPathToTheBase().size() == 0)
								return NoOpAction.NO_OP;
							envMap.comingBackHomeNO_Dirty = true;
							move = envMap.getPathToTheBase().remove(0);
							movePrec = move;
							return new DynamicAction(move);
						} else {
							move = getNewMove(vep);
							if (move.equals("noop"))
								return NoOpAction.NO_OP;
							return new DynamicAction(move);
						}
					case NOHOME_DIRTY:
						// in alcuni casi potrebbe non tornare al centro
						// perch�
						// non ha abbastanza energia
						if (envMap.probFindingHome(vep.getCurrentEnergy()) <= THRESHOLD_NOHOME_DIRTY) {
							if (solution != null) {
								count++;
								return solution.get(count);
							}
							envMap.setBase(envMap.getMinRectCentre());
							// System.err.println(vep.getCurrentEnergy());
							// il corrente non viene calcolato correttamente
							// perch� move e moveprec non vengono aggiornati
							AgentsManager solver = envMap.prepareStuffForSolver(vep.getCurrentEnergy(), false);
							solution = solver.solve();
							return solution.get(0);
						} else {
							return new DynamicAction(getNewMove(vep));
						}

					case HOME_DIRTY:

						if (solution != null) {
							count++;
							DynamicAction act = (DynamicAction) solution.get(count);
							if (!act.getName().equals("suck")) {
								move = act.getName();
								movePrec = move;
							}
							if (count == solution.size() - 2) {
								dirtyFound = false;
								solution = null;
								count = 1;
								envMap.comingBackHome = false;
							}
							return act;
						}
						if (lastState == AgentState.NOHOME_DIRTY) {
							AgentsManager solver = envMap.prepareStuffForSolver(vep.getCurrentEnergy(), true);
							solution = solver.solve();
							String solverMove = ((DynamicAction) solution.get(0)).getName();
							if (!solverMove.equals("suck")) {
								move = solverMove;
								movePrec = move;
							}
							return solution.get(0);

						} else {
							if (!envMap.comingBackHome)
								envMap.setPathToTheBase();
							if (vep.getCurrentEnergy() <= envMap.getPathToTheBase().size() + 1) {
								if (envMap.getPathToTheBase().size() == 0)
									return NoOpAction.NO_OP;
								envMap.comingBackHome = true;
								move = envMap.getPathToTheBase().remove(0);
								movePrec = move;
								return new DynamicAction(move);
							} else {
								if (vep.getState().getLocState() == LocationState.Dirty) {
									movePrec = "suck";
									return new DynamicAction("suck");
								}
								move = getNewMove(vep);
								if (move.equals("noop"))
									return NoOpAction.NO_OP;
								return new DynamicAction(move);
							}
						}

					default:
						return NoOpAction.NO_OP;
					}

				}
				return new DynamicAction(move);
			}

		});

		count = 0;
		movePrec = new String();
		firstStep = true;
		solution = null;
		THRESHOLD_NOHOME_NODIRTY = 0.2;
		THRESHOLD_NOHOME_DIRTY = 0.2;
		currentState = AgentState.NOHOME_NODIRTY;
		lastState = AgentState.NOHOME_NODIRTY;
		solution = null;
		homeFound = false;
		dirtyFound = false;
	}

	private static void printState() {
		switch (currentState) {
		case HOME_DIRTY:
			System.err.println("current : HOME_DIRTY");
			break;
		case NOHOME_NODIRTY:
			System.err.println("current : NOHOME_NODIRTY");
			break;
		case NOHOME_DIRTY:
			System.err.println("current : NOHOME_DIRTY");
			break;
		case HOME_NODIRTY:
			System.err.println("current : HOME_NODIRTY");
			break;

		default:
			break;
		}
	}

	private static String getNewMove(final LocalVacuumEnvironmentPerceptTaskEnvironmentB vep) {
		String move;
		move = envMap.getNextMove(vep.getCurrentEnergy());
		movePrec = move;

		return move;
	}

	private static void updateMap(final LocalVacuumEnvironmentPerceptTaskEnvironmentB vep) {
		if (vep.getState().getLocState() == LocationState.Dirty) {
			dirtyFound = true;
			ChangeState();
		}

		if (vep.isMovedLastTime()) {
			envMap.addElementMap(movePrec, vep.getState().getLocState());
		} else {
			envMap.addElementMap(movePrec, LocationState.Obstacle);
		}

		if (vep.isOnBase()) {
			homeFound = true;
			envMap.setBase(envMap.getCurrent());
			ChangeState();
		}
	}

	private static void ChangeState() {
		if (homeFound) {
			if (dirtyFound) {
				lastState = currentState;
				currentState = AgentState.HOME_DIRTY;
			} else {
				currentState = AgentState.HOME_NODIRTY;
			}
		} else {
			if (dirtyFound) {
				currentState = AgentState.NOHOME_DIRTY;
			} else {
				currentState = AgentState.NOHOME_NODIRTY;
			}
		}
	}

}
